import re
import heapq

from collections import defaultdict
from datetime import datetime
from collections import Counter
import matplotlib.pyplot as plt
import numpy as np

# 正则表达式来提取时间和地址
timestamp_pattern = re.compile(r"\[(.*?)\]")
address_pattern = re.compile(r"0x([0-9a-fA-F]+);")

# 分析数据
def analyze_log(log_lines):
    write_operations = []
    erase_operations = []
    timestamps = []
    addresses = []

    for line in log_lines:
        # 提取时间戳
        timestamp_match = timestamp_pattern.search(line)
        if timestamp_match:
            timestamps.append(datetime.strptime(timestamp_match.group(1), "%Y-%m-%d %H:%M:%S.%f"))

        # 提取地址
        address_match = address_pattern.search(line)
        if address_match:
            addresses.append(address_match.group(1))

        # 分别统计写操作和擦除操作
        if "(NvmProgramWords)" in line or "(ctd_flash_erase_write_page)" in line:
            write_operations.append((line, address_match.group(1)))
        elif "(ctd_flash_erase_page)" in line:
            erase_operations.append((line, address_match.group(1)))

    return timestamps, addresses, write_operations, erase_operations

# 计算高频时间段和地址段
def find_frequent_intervals(items, get_key=lambda x: x):
    frequency = defaultdict(int)
    for item in items:
        key = get_key(item)
        frequency[key] += 1

    most_frequent = max(frequency, key=frequency.get) if frequency else None
    return most_frequent, frequency

log_lines_example = [

    "I/log [2024-2-27 6:20:19.924500] ((ctd_flash_erase_page) ) 0x0c000000;0x200",
    "I/log [2024-2-27 6:20:19.924500] ((ctd_flash_erase_page) ) 0x0c000000;0x200",
    "I/log [2024-2-27 6:20:19.924700] ((ctd_flash_erase_page) ) 0x0c100000;0x200",
    "I/log [2024-2-27 6:20:19.924700] ((ctd_flash_erase_page) ) 0x0c100000;0x200",
    "I/log [2024-2-27 6:20:19.924700] ((ctd_flash_erase_page) ) 0x0c200000;0x200",

    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c012000;0x200",
    "I/log [2024-2-27 6:20:19.924700] ((ctd_flash_write_page) ) 0x0c200000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c102000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c102000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c102000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002000;0x200",
    "I/log [2024-2-27 6:20:19.924900] (ctd_flash_write_page) 0x0c002200;0x200",
]

# 解析日志行中的地址
def extract_address(log_line):
    match = re.search(r'0x[0-9a-fA-F]+', log_line)
    if match:
        return int(match.group(), 16)  # 将十六进制地址转换为整数
    return None

def nvm_ana(log_lines):
    # 定义正则表达式模式并编译以提高性能
    address_re = re.compile(r'0x([0-9a-fA-F]+);')
    write_re = re.compile(r'ctd_flash_write_page|NvmProgramWords')
    erase_re = re.compile(r'(ctd_flash_erase_page)')

    # 定义页大小
    PAGE_SIZE = 512

    # 初始化计数器
    write_counts = Counter()
    erase_counts = Counter()

    # 分析日志行
    for line in log_lines:
        address_match = address_re.search(line)
        if address_match:
            address = int(address_match.group(1), 16)
            page = address // PAGE_SIZE * PAGE_SIZE  # 分配到页

            # 检查写操作
            if write_re.search(line):
                write_counts[page] += 1

            # 检查擦除操作
            if erase_re.search(line):
                erase_counts[page] += 1

    # 获取 write_counts 中最大的前10个值及其对应的page地址
    top_10_writes = heapq.nlargest(10, write_counts.items(), key=lambda x: x[1])

    # 打印结果
    print("最大的前10个写操作计数及其对应的page地址：")
    for page, count in top_10_writes:
        print(f"Page 0x{page:08X}: {count} write operations")

    # 获取 write_counts 中最大的前10个值及其对应的page地址
    top_10_erases = heapq.nlargest(10, erase_counts.items(), key=lambda x: x[1])

    # 打印结果
    print("最大的前10个擦操作计数及其对应的page地址：")
    for page, count in top_10_erases:
        print(f"Page 0x{page:08X}: {count} write operations")

    # 转换为列表以便绘图
    write_pages = list(write_counts.keys())
    write_counts = list(write_counts.values())

    erase_pages = list(erase_counts.keys())
    erase_counts = list(erase_counts.values())

    # 绘制柱状图
    plt.figure(figsize=(50, 10))  # 增加一些高度以适应两个子图

    # 写操作的柱状图
    plt.subplot(1, 2, 1)
    bars=plt.bar(write_pages, write_counts, width=1, color='b', label='Write Operations')
    plt.xlabel('Address')
    plt.ylabel('Frequency')
    plt.title('Write Operations by Address')

    # 获取每个柱子的顶部位置和宽度
    tops = [bar.get_height() for bar in bars]
    lefts = [bar.get_x() + bar.get_width() / 2 for bar in bars]  # 移动到柱子的中心

    # 绘制顶部点
    # plt.plot(lefts, tops, color='r', marker='o', linestyle='None', label='Top Markers')
    # 绘制顶部点，设置点的大小为非常小的值
    plt.scatter(lefts, tops, color='r', marker='o', s=2)  # s 参数控制点的大小

    # 设置x轴刻度位置和标签
    plt.xticks(write_pages,[f'0x{page:08X}' for page in write_pages], rotation=45, fontsize=4)
    # 在柱状图顶部显示y轴数值
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width()/2, height + 0.05 * max(write_counts), f'{height:.2f}',
                 ha='center', va='bottom', color='black', rotation=45, fontsize=4)
    plt.legend()

    # 擦除操作的柱状图
    plt.subplot(1, 2, 2)
    bars=plt.bar(erase_pages, erase_counts, width=PAGE_SIZE, color='r', label='Erase Operations')
    plt.xlabel('Address')
    plt.ylabel('Frequency')
    plt.title('Erase Operations by Address')

    # 获取每个柱子的顶部位置和宽度
    tops = [bar.get_height() for bar in bars]
    lefts = [bar.get_x() for bar in bars]

    # 绘制顶部连线
    plt.plot(lefts, tops, color='r', marker='o', linestyle='-', label='Connected Line')

    # 设置x轴刻度位置和标签
    plt.xticks(erase_pages, [f'0x{page:08X}' for page in erase_pages], rotation=45)
    # 在柱状图顶部显示y轴数值
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width()/2, height + 0.05 * max(write_counts), f'{height:.2f}',
                 ha='center', va='bottom', color='black', rotation=45)
    plt.legend()

    # 调整布局和显示图表
    plt.tight_layout()
    plt.savefig('nvm_operations.pdf')  # 保存图像到文件
    plt.show()


# 主函数
def main():

    # 日志文件路径
    log_file_path = 'nvm.log'

    with open(log_file_path, 'r') as file:
        log_lines = file.readlines()

    timestamps, addresses, write_operations, erase_operations = analyze_log(log_lines)

    # 分析时间戳来找出高频更新的时间段
    most_frequent_time, time_frequency = find_frequent_intervals(timestamps, get_key=lambda x: x.strftime("%H:%M:%S"))
    print(f"Most frequent time interval: {most_frequent_time}, Frequency: {time_frequency[most_frequent_time]}")

    # 分析地址来找出高频更新的地址段
    most_frequent_address, address_frequency = find_frequent_intervals(addresses)
    print(f"Most frequent address interval: {most_frequent_address}, Frequency: {address_frequency[most_frequent_address]}")

    # 分开统计写操作和擦除操作
    write_addresses = [addr for _, addr in write_operations]
    erase_addresses = [addr for _, addr in erase_operations]

    most_frequent_write_address, write_frequency = find_frequent_intervals(write_addresses)
    print(f"Most frequent write address: {most_frequent_write_address}, Frequency: {write_frequency[most_frequent_write_address]}")

    most_frequent_erase_address, erase_frequency = find_frequent_intervals(erase_addresses)
    print(f"Most frequent erase address: {most_frequent_erase_address}, Frequency: {erase_frequency[most_frequent_erase_address]}")

    # 对日志行进行排序,自动跳过不匹配行
    sorted_log_lines = sorted(log_lines, key=lambda line: (extract_address(line) is not None, extract_address(line)))
    # sorted_log_lines = sorted(log_lines, key=lambda line: extract_address(line))
    nvm_ana(log_lines)

if __name__ == "__main__":
    main()
